/*
 *
 */
package org.jiscinvolve.astrodabis.barberry.hibernate.data.normal;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.Serializable;

import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
import javax.persistence.GenerationType;
import javax.persistence.GeneratedValue;

import org.hibernate.annotations.Index;
import org.hibernate.annotations.NamedQuery;
import org.hibernate.annotations.NamedQueries;
import org.hibernate.annotations.GenericGenerator;

import org.springframework.stereotype.Repository;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional; 

import org.jiscinvolve.astrodabis.barberry.common.core.Job;
import org.jiscinvolve.astrodabis.barberry.common.core.Tag;
import org.jiscinvolve.astrodabis.barberry.common.core.Womble;
import org.jiscinvolve.astrodabis.barberry.common.core.Account;
import org.jiscinvolve.astrodabis.barberry.common.core.Identifier;
import org.jiscinvolve.astrodabis.barberry.common.core.SimpleIdent;
import org.jiscinvolve.astrodabis.barberry.common.core.AbstractIdent;
import org.jiscinvolve.astrodabis.barberry.common.core.exception.*;

import org.jiscinvolve.astrodabis.barberry.common.data.TapRow;
import org.jiscinvolve.astrodabis.barberry.common.data.TapJoin;
import org.jiscinvolve.astrodabis.barberry.common.data.TapTable;
import org.jiscinvolve.astrodabis.barberry.common.data.TapColumn;
import org.jiscinvolve.astrodabis.barberry.common.data.TapService;

import org.jiscinvolve.astrodabis.barberry.common.data.RowTag;

import org.jiscinvolve.astrodabis.barberry.hibernate.core.AbstractEntity;
import org.jiscinvolve.astrodabis.barberry.hibernate.core.AbstractFactory;

import org.jiscinvolve.astrodabis.barberry.hibernate.data.TapColumnEntity;

import org.jiscinvolve.astrodabis.barberry.hibernate.annotation.*;

/**
 *
 */
@Entity
@Table(
    name = TapRowEntity.DB_TABLE_NAME
    )
@org.hibernate.annotations.Table(
    appliesTo = TapRowEntity.DB_TABLE_NAME,
    indexes = {
        @Index(
            name = TapRowEntity.DB_INDEX_NAME,
            columnNames = {
                TapRowEntity.DB_PARENT_COL,
                TapRowEntity.DB_VALUE_COL
                }
            )
        }
    )
@NamedQueries(
        {
        @NamedQuery(
            name  = "taprow-all",
            query = "FROM TapRowEntity"
            ),
        @NamedQuery(
            name  = "taprow-parent",
            query = "FROM TapRowEntity WHERE parent = :parent"
            ),
        @NamedQuery(
            name  = "taprow-parent-value",
            query = "FROM TapRowEntity WHERE parent = :parent AND value = :value"
            )
        }
    )
public class TapRowEntity
extends AbstractEntity
implements TapRow
    {

    /**
     * Our debug logger.
     * 
     */
    private static Log log = LogFactory.getLog(TapRowEntity.class);

    public static final String DB_TABLE_NAME = "normrows";
    public static final String DB_INDEX_NAME = "normrows_index";
    public static final String DB_IDENT_COL  = "ident";
    public static final String DB_PARENT_COL = "parent";
    public static final String DB_VALUE_COL  = "rowkey";

    @Repository
    public static class Factory
    extends AbstractFactory<TapRow, TapRowEntity>
    implements TapRow.Factory
        {

        @Override
        public Identifier ident(String ident)
            {
            if ((ident == null) || ("-".equals(ident)))
                {
                return null ;
                }
            else {
                try {
                    return new SimpleIdent<Long>(
                        Long.valueOf(
                            ident
                            )
                        );
                    }
                catch (NumberFormatException ouch)
                    {
                    throw new IdentFormatException(
                        ouch
                        );
                    }
                }
            }

        @Override
        @CreateObject
        public TapRow create(TapColumn parent, String value)
            {
            return createQuick(
                parent,
                value
                );
            }
            
        @Override
        @CreateQuick
        public TapRow createQuick(TapColumn parent, String value)
            {
            TapRow found = select(
                parent,
                value
                );
            if (found != null)
                {
                return found ;
                }
            else {
                return hibernate().insert(
                    new TapRowEntity(
                        parent,
                        value
                        )
                    );
                }
            }

        @Override
        @SelectObject
        public TapRow select(Identifier ident)
            {
            return hibernate().select(
                TapRowEntity.class,
                ident
                );
            }

        @Override
        @SelectObject
        public Iterable<TapRow> select()
            {
            return hibernate().iterable(
                hibernate().query(
                    "taprow-all"
                    )
                );
            }


        @Override
        @SelectObject
        public Iterable<TapRow> select(TapColumn parent)
            {
            return hibernate().iterable(
                hibernate().query(
                    "taprow-parent"
                    ).setEntity(
                        "parent",
                        parent
                        )
                );
            }

        @Override
        @SelectObject
        public TapRow select(TapColumn parent, String value)
            {
            return hibernate().first(
                hibernate().query(
                    "taprow-parent-value"
                    ).setEntity(
                        "parent",
                        parent
                    ).setString(
                        "value",
                        value
                        )
                );
            }
        }

    protected TapRowEntity()
        {
        super();
        }

    protected TapRowEntity(TapColumn parent, String value)
        {
        super(true);
        this.value  = value  ;
        this.parent = parent ;
        }

    @Id
    @Column(
        name = DB_IDENT_COL
        )
    @GeneratedValue(
        generator="tapdata-hilo"
        )
    @GenericGenerator(
        name="tapdata-hilo",
        strategy="hilo"
        )
    protected Long ident ;

    @Override
    public Identifier ident()
        {
        return new AbstractIdent()
            {
            @Override
            public Serializable value()
                {
                return ident ;
                }
            };
        }

    @ManyToOne(
        fetch = FetchType.LAZY,
        targetEntity = TapColumnEntity.class
        )
    @JoinColumn(
        name = DB_PARENT_COL,
        unique = false,
        nullable = false,
        updatable = false
        )
    private TapColumn parent ;

    @Override
    public TapColumn parent()
        {
        return this.parent ;
        }

    @Basic(
        fetch = FetchType.LAZY
        )
    @Column(
        name = DB_VALUE_COL,
        unique = false,
        nullable = false,
        updatable = false
        )
    private String value ;

    @Override
    public String value()
        {
        return this.value ;
        }

    @Override
    public boolean equals(Object that)
        {
log.debug("TapRowEntity.equals(Object)");
        if (this == that)
            {
log.debug("this == that");
            return true ;
            }
        if (this.ident == null)
            {
log.debug("this.ident == null");
            return false ;
            }
        if (that instanceof TapRowEntity)
            {
log.debug("that instanceof TapRowEntity");
            return this.ident.equals(
                ((TapRowEntity)that).ident
                );
            }
        if (that instanceof TapRow)
            {
log.debug("that instanceof TapRow");
            return this.ident().equals(
                ((TapRow)that).ident()
                );
            }
        return false ;
        }


    public RowTags tags()
        {
        return new RowTags()
            {

            @Override
            public RowTag create(Job job, Tag tag)
                {
                return Womble.womble().rowtags().create(
                    TapRowEntity.this,
                    job,
                    tag
                    );
                }

            @Override
            public RowTag createQuick(Job job, Tag tag)
                {
                return Womble.womble().rowtags().createQuick(
                    TapRowEntity.this,
                    job,
                    tag
                    );
                }

            @Override
            public RowTag create(Job job, Tag tag, Double value)
                {
                return Womble.womble().rowtags().create(
                    TapRowEntity.this,
                    job,
                    tag,
                    value
                    );
                }

            @Override
            public RowTag createQuick(Job job, Tag tag, Double value)
                {
                return Womble.womble().rowtags().createQuick(
                    TapRowEntity.this,
                    job,
                    tag,
                    value
                    );
                }

            @Override
            public Iterable<RowTag> select()
                {
                return Womble.womble().rowtags().select(
                    TapRowEntity.this
                    );
                }

            @Override
            public Iterable<RowTag> select(Tag tag)
                {
                return Womble.womble().rowtags().select(
                    TapRowEntity.this,
                    tag
                    );
                }

            @Override
            public RowTag select(Identifier ident)
                {
                return Womble.womble().rowtags().select(
                    ident
                    );
                }
            };
        }

    public TapJoins joins()
        {
        return new TapJoins()
            {

            @Override
            public TapJoin create(TapRow row)
                {
                return Womble.womble().joins().create(
                    TapRowEntity.this,
                    row
                    );
                }

            @Override
            public TapJoin createQuick(TapRow row)
                {
                return Womble.womble().joins().createQuick(
                    TapRowEntity.this,
                    row
                    );
                }

            @Override
            public TapJoin select(TapRow row)
                {
                return Womble.womble().joins().select(
                    TapRowEntity.this,
                    row
                    );
                }

            @Override
            public Iterable<TapJoin> select(TapJoin.SelectType type)
                {
                return Womble.womble().joins().select(
                    TapRowEntity.this,
                    type
                    );
                }

            @Override
            public Iterable<TapJoin> select(TapRow row, TapJoin.SelectType type)
                {
                return Womble.womble().joins().select(
                    TapRowEntity.this,
                    row,
                    type
                    );
                }

            @Override
            public TapJoin select(Identifier ident)
                {
                return Womble.womble().joins().select(
                    ident
                    );
                }
            };
        }

    @Override
    public String toString()
        {
        StringBuilder builder = new StringBuilder();
        builder.append(
            "Row["
            );
        builder.append(
            this.ident
            );
        builder.append(
            "]{ "
            );
        builder.append(
            this.parent().toString()
            );
        builder.append(
            ", value{"
            );
        builder.append(
            this.value()
            );
        builder.append(
            "}}"
            );
        return builder.toString();
        }
    }

